import java.io.*;

/**
 * Recurse the specified directory, loads the java files in that directory,
 * removes everything from the it except class hierarchy information and 
 * writes it to the specified output directory.
 */
public class RemoveComment
{
	private boolean recurse;

	public RemoveComment(String inDir, String outDir, boolean recurse)
		throws IOException
	{
		this.recurse = recurse;
		generate(new File(inDir), new File(outDir));
	}

	private void generate(File inDir, File outDir)
		throws IOException
	{
		System.out.println("Processing :: " + inDir.getCanonicalPath());

		// create the output directory if not existing.
		if ( !outDir.exists() )
			outDir.mkdir();

		// get the list of file names in inDir.
		File[] javaFiles = getSourceFiles(inDir);

		File inFile;
		File outFile;
		for(int i = 0; i < javaFiles.length; i ++ )
		{
			inFile  = javaFiles[i];
			outFile = new File(outDir, inFile.getName());

			System.out.println("Generating :: " + outFile.getCanonicalPath() );
			generateFile(inFile,outFile);
		}

		if ( this.recurse )
		{
			File[] dirs = getDirectories(inDir);
			File nextInDir;
			File nextOutDir;
			for(int i = 0 ; i < dirs.length; i ++ )
			{
				nextInDir = dirs[i];
				nextOutDir = new File(outDir, nextInDir.getName() );
				generate(nextInDir, nextOutDir);
			}
		}
	}


	private void generateFile(File inFile, File outFile)
		throws IOException
	{
		BufferedReader rd = new BufferedReader(new FileReader(inFile));
		BufferedWriter wt = new BufferedWriter(new FileWriter(outFile));

		boolean done = false;
		String readLine;
		String writeLine;

		comment = false;
		while(!done)
		{
		   try
		   {
		      readLine = rd.readLine();
		      if ( readLine == null )
		        done = true;

		      if (  ( readLine != null ) &&
		            ( readLine.equals("") )
		         )
		      {
		         wt.write(readLine);
		         wt.newLine();
		      }
		      else
		      {

		         writeLine = processLine(readLine);
		         if ( writeLine != null )
		         {
		            if ( !writeLine.equals("") )
		            {
		               wt.write(writeLine, 0, writeLine.length());
		               wt.newLine();
		            }
		         }
		      }
		   }
		   catch(IOException e)
		   {
		      done = true;
		   }
		}

		try { wt.close(); } catch(IOException e1){}
		try { rd.close(); } catch(IOException e2){}
	}

	private boolean comment;
	private String processLine(String inLine)
	{
	    //System.out.println("Prcessing " + inLine );
	    if ( inLine == null ) return inLine;

	   int cEnd;
	   int cStart;
	   int cLine;
	   String outLine = null;
	   String outLine1 = null;

	   cEnd   = inLine.indexOf("*/");
	   cStart = inLine.indexOf("/*");
	   cLine  = inLine.indexOf("//");

	   if ( comment )
	   {
	      if ( cEnd != -1 )
	      {
	         // process the remaining line.
	         comment = false;
	         outLine = processLine(inLine.substring(cEnd + 2, inLine.length()));
	      }
	   }
	   else // start else OF if (comment)
	   {
	      if ( ( cLine == -1 ) && ( cStart == -1 ) )
	      {
	        outLine = inLine;
	        return outLine;
	      }

	      // either /* or // in the line.

	      if ( cLine == -1 )
	      {
	         ///* in the line.
	         // because cStart != -1
	         comment = true;
	         outLine  = inLine.substring(0, cStart);
	         outLine1 = 
	            processLine(inLine.substring(cStart+2, inLine.length()));

	         if ( outLine1 != null )
	           outLine = outLine + outLine1;
	      }

	      if ( cStart == -1 )
	      {
	         // // in the line.
	         // trash the line after //
	         outLine = inLine.substring(0, cLine);
	      }

	      if ( ( cStart != -1 ) && ( cLine != -1 ) )
	      {
	         // both // and /* in the line.

	         if ( cLine < cStart )
	         {
	            outLine = inLine.substring(0, cLine);
	         }
	         else
	         {
	            comment = true;
	            outLine  = inLine.substring(0, cStart);
	            outLine1 = 
	              processLine(inLine.substring(cStart+2,inLine.length()));

	            if ( outLine1 != null ) 
	              outLine = outLine + outLine1;
	         }
	      }

	   } // end else OF if ( comment )

	   return outLine;
	} // end processLine

	private File[] getSourceFiles(File directory)
	{
		String[] allFiles = directory.list(javaFilter);
		File[] javaFiles = new File[allFiles.length];
		for(int i = 0; i < allFiles.length; i ++ )
			javaFiles[i] = new File(directory, allFiles[i]);

		return javaFiles;
	}

	private File[] getDirectories(File directory)
	{
		String[] allDir = directory.list(dirFilter);
		File[] dirs = new File[allDir.length];
		for( int i = 0; i < allDir.length; i ++ )
			dirs[i] = new File(directory, allDir[i]);
		
		return dirs;
	}

	private DirFileFilter dirFilter = new DirFileFilter();
	private JavaFileFilter javaFilter = new JavaFileFilter();

	class JavaFileFilter implements FilenameFilter
	{
		public boolean accept(File dir, String fileName)
		{
			File tmpFile = new File(dir, fileName);
			if ( tmpFile.isFile() && (fileName.indexOf(".java") != -1 ))
				return true;
			else
				return false;
		}
	}

	class DirFileFilter implements FilenameFilter
	{
		public boolean accept(File dir, String fileName)
		{
			File tmpFile = new File(dir, fileName);
			return  tmpFile.isDirectory(); 
		}
	}

	public static void main(String[] args)
		throws IOException
	{
		if ( args.length < 2 ) 
		{
		   System.out.println("Usage :: RemoveComment <sourcedir> <destinationdir>");
		   System.out.println();
		   System.out.println("<sourcedir>       -  Directory where the java files are located (recurses the directory)");
		   System.out.println();
		   System.out.println("<destinationdir>  -  Directory where the processed java files are to be stored. (retains the source directory structure)");
		   System.out.println();
		   System.out.println();
		   System.out.println("RemoveComment removes comments from the java files contained in the specified directory. The processed files are written in the destination directory");
         return;
		}

		new RemoveComment(args[0], args[1], true);
	}
}
